namespace SimpleWebServices.Configuration
{
    using System;
    using System.Configuration;
    using System.Xml;
    using SimpleWebServices.Data;
    using Xunit;

    public sealed class RepositoryConfigurationFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<RepositoryConfiguration>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .Implements<IConfigurationSectionHandler>()
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new RepositoryConfiguration());
        }

        [Fact]
        public void op_Clear()
        {
            RepositoryConfiguration.Clear();

            try
            {
                Assert.Empty(RepositoryConfiguration.Settings());

                RepositoryConfiguration.Settings().Add("<repository key='Example'>Example.Repository</repository>".Deserialize<RepositorySetting>());

                Assert.NotEmpty(RepositoryConfiguration.Settings());
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_Reset()
        {
            int expected = RepositoryConfiguration.Settings().Count;

            RepositoryConfiguration.Clear();

            Assert.Empty(RepositoryConfiguration.Settings());

            RepositoryConfiguration.Reset();

            int actual = RepositoryConfiguration.Settings().Count;

            Assert.Equal<int>(expected, actual);
        }
        
        [Fact]
        public void op_ResolveOfT()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<TestRecord>();

                Assert.NotNull(RepositoryConfiguration.Resolve<TestRecord>());
            }
            finally
            {
                FakeRepository.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string()
        {
            RepositoryConfiguration.Clear();

            try
            {
                string xml = "<repository key='" + typeof(TestRecord).Name + "' urn='urn://example.com/'>Example.Repository</repository>";

                RepositoryConfiguration.Settings().Add(xml.Deserialize<RepositorySetting>());

                AbsoluteUri expected = "urn://example.com/test";

                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("test"));
                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string_whenUrnWithoutSlash()
        {
            RepositoryConfiguration.Clear();

            try
            {
                string xml = "<repository key='" + typeof(TestRecord).Name + "' urn='urn://example.com'>Example.Repository</repository>";

                RepositoryConfiguration.Settings().Add(xml.Deserialize<RepositorySetting>());

                AbsoluteUri expected = "urn://example.com/test";

                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("test"));
                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string_whenDefaultUrn()
        {
            RepositoryConfiguration.Clear();

            try
            {
                string xml = "<repository key='" + typeof(TestRecord).Name + "'>Example.Repository</repository>";

                RepositoryConfiguration.Settings().Add(xml.Deserialize<RepositorySetting>());
                RepositoryConfiguration.Settings().Urn = "urn://example.com";

                AbsoluteUri expected = "urn://example.com/test";

                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("test"));
                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string_whenNoSetting()
        {
            RepositoryConfiguration.Clear();

            try
            {
                RepositoryConfiguration.Settings().Urn = "urn://example.com";

                AbsoluteUri expected = "urn://example.com/test";

                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("test"));
                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string_whenNoSettingAndNoDefault()
        {
            RepositoryConfiguration.Clear();

            try
            {
                Assert.Throws<ArgumentNullException>(() => RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string_whenEmptyDefault()
        {
            RepositoryConfiguration.Clear();

            try
            {
                RepositoryConfiguration.Settings().Urn = string.Empty;

                Assert.Throws<ArgumentOutOfRangeException>(() => RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_string_whenEmptySetting()
        {
            RepositoryConfiguration.Clear();

            try
            {
                string xml = "<repository key='" + typeof(TestRecord).Name + "' urn=''>Example.Repository</repository>";

                RepositoryConfiguration.Settings().Add(xml.Deserialize<RepositorySetting>());

                Assert.Throws<ArgumentOutOfRangeException>(() => RepositoryConfiguration.ToUrn<TestRecord>("/test"));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_stringNull()
        {
            RepositoryConfiguration.Clear();

            try
            {
                RepositoryConfiguration.Settings().Urn = "urn://example.com";

                AbsoluteUri expected = "urn://example.com/";

                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>(null as string));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_ToUrnOfT_stringEmpty()
        {
            RepositoryConfiguration.Clear();

            try
            {
                RepositoryConfiguration.Settings().Urn = "urn://example.com";

                AbsoluteUri expected = "urn://example.com/";

                Assert.Equal<AbsoluteUri>(expected, RepositoryConfiguration.ToUrn<TestRecord>(string.Empty));
            }
            finally
            {
                RepositoryConfiguration.Reset();
            }
        }

        [Fact]
        public void op_Settings()
        {
            Assert.NotNull(RepositoryConfiguration.Settings());
        }

        [Fact]
        public void op_Settings_string()
        {
            Assert.NotNull(RepositoryConfiguration.Settings("simplewebservices/repositories"));
        }

        [Fact]
        public void op_Create_object_object_XmlNodeNull()
        {
            RepositorySettingCollection actual = new RepositoryConfiguration().Create(null, null, null as XmlNode) as RepositorySettingCollection;

            Assert.Empty(actual);
        }

        [Fact]
        public void op_Create_object_object_XmlNodeEmpty()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml("<repositories />");

            RepositorySettingCollection actual = new RepositoryConfiguration().Create(null, null, xml.DocumentElement) as RepositorySettingCollection;

            Assert.Empty(actual);
        }

        [Fact]
        public void op_Create_object_object_XmlNode()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(
                "<repositories default='Default.Repository'>" +
                    "<repository key='Example1'>Example1.Repository</repository>" +
                    "<repository key='Example2'>Example2.Repository</repository>" +
                "</repositories>");

            RepositorySettingCollection actual = new RepositoryConfiguration().Create(null, null, xml.DocumentElement) as RepositorySettingCollection;

            Assert.Equal<string>("Default.Repository", actual.Default);
            Assert.NotEmpty(actual);
        }

        [Fact]
        public void op_Create_object_object_XmlNodeInvalid()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml("<bad-name/>");

            Assert.Throws<ConfigurationErrorsException>(() => new RepositoryConfiguration().Create(null, null, xml.DocumentElement));
        }
    }
}